import pygame
import sys
import os
from typing import List, Optional
from .button import Button
from .music_player import MusicPlayer

# 添加父目录到系统路径
current_dir = os.path.dirname(os.path.abspath(__file__))
parent_dir = os.path.dirname(current_dir)
sys.path.append(parent_dir)

from constant import Setting


# ---------------------- 先定义装备类和角色类（与你的属性匹配） ----------------------
#for test
class Equipment:
    """装备类（按你的属性定义）"""
    def __init__(self, name: str, image_path: str, is_equipped: bool, atk: int, defense: int, speed: int, equip_type: str = "general"):
        self.name = name                  # 装备名称
        self.image_path = image_path      # 装备图片路径
        self.is_equipped = is_equipped    # 是否已装备
        self.atk = atk                    # 攻击力
        self.defense = defense            # 防御力
        self.speed = speed                # 速度
        self.equip_type = equip_type      # 装备类型（用于限制同类装备只能装备一个）


class Character:
    """角色类（按你的属性定义，包含装备列表）"""
    def __init__(self, name: str, hp: int, max_hp: int, atk: int, defense: int, speed: int, 
                 image_big_path: str, equipments: Optional[List[Equipment]] = None):
        self.name = name                  # 角色名称
        self.hp = hp                      # 当前生命值
        self.max_hp = max_hp              # 最大生命值
        self.atk = atk                    # 基础攻击力（不含装备）
        self.defense = defense            # 基础防御力（不含装备）
        self.speed = speed                # 基础速度（不含装备）
        self.image_big_path = image_big_path  # 角色大图路径（物品栏用）
        self.equipments = equipments if equipments else []  # 外部接入的装备列表

    def get_total_atk(self) -> int:
        """计算总攻击力（基础+已装备装备的atk）"""
        total = self.atk
        for equip in self.equipments:
            if equip.is_equipped:
                total += equip.atk
        return total

    def get_total_defense(self) -> int:
        """计算总防御力（基础+已装备装备的defense）"""
        total = self.defense
        for equip in self.equipments:
            if equip.is_equipped:
                total += equip.defense
        return total

    def get_total_speed(self) -> int:
        """计算总速度（基础+已装备装备的speed）"""
        total = self.speed
        for equip in self.equipments:
            if equip.is_equipped:
                total += equip.speed
        return total

    def unequip_same_type(self, equip_type: str):
        """卸下同一类型的所有装备"""
        for equip in self.equipments:
            if equip.equip_type == equip_type and equip.is_equipped:
                equip.is_equipped = False


# ---------------------- 地图界面类（支持外部接入角色和装备） ----------------------
class MapUI:
    """地图界面类（支持从外部接入角色实例，自动读取角色的装备列表）"""
    def __init__(self, player: Character):
        pygame.init()
        self.settings = Setting()
        self.root_dir = parent_dir

        # 核心：接收外部传入的角色实例（含装备列表）
        self.player = player
        # 从角色实例中获取装备列表（外部接入的核心逻辑）
        self.equipments = self.player.equipment_deck

        # 屏幕设置
        self.screen = pygame.display.set_mode(
            (self.settings.screen_width, self.settings.screen_height)
        )
        pygame.display.set_caption(f"{self.settings.screen_title} - Map")

        # 核心状态控制
        self.running = True
        self.is_inventory_open = False  # 是否显示物品栏弹窗

        # 加载资源（优先使用角色实例中的图片路径）
        self.map_background = self._load_map_background()
        self.inventory_btn_image = self._load_inventory_btn_image()  # 物品栏按钮图（items.png）
        self.inventory_bg_image = self._load_inventory_bg_image()    # 物品栏弹窗背景
        self.player_img = self._load_player_image()                  # 角色大图（从角色实例获取路径）

        # 初始化界面元素（装备槽自动根据角色的装备列表数量生成）
        self.level_buttons = self._create_level_buttons()
        self.inventory_button = self._create_inventory_button()      # 右下角物品栏按钮
        self.inventory_elements = self._init_inventory_elements()    # 物品栏弹窗元素（含装备槽）
        
        #music_player
        self.music_player = MusicPlayer()

        # 跳转接口：战斗界面跳转函数（外部传入）
        self.battle_jump_func = None

    def _load_map_background(self):
        """加载地图背景图（从constant配置获取路径）"""
        try:
            map_path = os.path.join(self.root_dir, self.settings.images_path["map_background"])
            background = pygame.image.load(map_path).convert()
            return pygame.transform.scale(background, (self.settings.screen_width, self.settings.screen_height))
        except FileNotFoundError:
            print(f"【错误】未找到地图背景图: {map_path}")
            fallback_surf = pygame.Surface((self.settings.screen_width, self.settings.screen_height))
            fallback_surf.fill(self.settings.bg_path_map)
            return fallback_surf

    def _load_inventory_btn_image(self):
        """加载物品栏按钮图片（固定路径：image/items.png）"""
        try:
            btn_path = os.path.join(self.root_dir, "image/items.png")
            img = pygame.image.load(btn_path).convert_alpha()
            return pygame.transform.scale(img, (80, 80))  # 按钮尺寸80x80
        except FileNotFoundError:
            print(f"【错误】未找到物品栏按钮图片: image/items.png")
            fallback_surf = pygame.Surface((80, 80), pygame.SRCALPHA)
            fallback_surf.fill((150, 150, 150, 200))
            return fallback_surf

    def _load_inventory_bg_image(self):
        """加载物品栏弹窗背景（固定路径：image/inventory_bg.png）"""
        try:
            bg_path = os.path.join(self.root_dir, self.settings.title_images_path["select_title"])
            img = pygame.image.load(bg_path).convert_alpha()
            # 弹窗尺寸：宽90%屏幕、高75%屏幕（适配5个装备）
            target_size = (int(self.settings.screen_width * 0.9), int(self.settings.screen_height * 0.75))
            return pygame.transform.scale(img, target_size)
        except FileNotFoundError:
            print(f"【错误】未找到物品栏弹窗背景图: image/inventory_bg.png")
            target_size = (int(self.settings.screen_width * 0.9), int(self.settings.screen_height * 0.75))
            fallback_surf = pygame.Surface(target_size, pygame.SRCALPHA)
            fallback_surf.fill((245, 245, 220, 230))  # 纸张色调半透明
            return fallback_surf

    def _load_player_image(self):
        """加载角色大图（从角色实例的image_big_path获取路径）"""
        try:
            img_path = os.path.join(self.root_dir, self.player.image_path)
            img = pygame.image.load(img_path).convert_alpha()
            return pygame.transform.scale(img, (220, 320))  # 角色图尺寸220x320
        except FileNotFoundError:
            print(f"【错误】未找到角色大图: {self.player.image_big_path}")
            fallback_surf = pygame.Surface((220, 320), pygame.SRCALPHA)
            fallback_surf.fill((100, 100, 100, 200))
            return fallback_surf

    def _create_level_buttons(self):
        """创建关卡1-5按钮（原有逻辑保留）"""
        level_buttons = []
        btn_width = self.settings.btn_small_width
        btn_height = self.settings.btn_small_height
        btn_img_path = os.path.join(self.root_dir, self.settings.button_images_path["start_ui_button"])

        # 关卡按钮坐标（按原配置）
        levels = [
            (0.46, 0.75, 1), (0.65, 0.62, 2),
            (0.65, 0.42, 3), (0.25, 0.45, 4),
            (0.45, 0.45, 5)
        ]

        for x_ratio, y_ratio, level_num in levels:
            btn_x = self.settings.screen_width * x_ratio
            btn_y = self.settings.screen_height * y_ratio
            btn = Button(
                x=btn_x, y=btn_y, width=btn_width, height=btn_height,
                text=f"level {level_num}", settings=self.settings,
                is_small=True, action=lambda num=level_num: self._on_level_click(num),
                image_path=btn_img_path
            )
            level_buttons.append(btn)
        return level_buttons

    def _create_inventory_button(self):
        """创建右下角物品栏按钮（无文字，仅图片）"""
        # 位置：右下角距边框30px
        btn_x = self.settings.screen_width - self.inventory_btn_image.get_width() - 30
        btn_y = self.settings.screen_height - self.inventory_btn_image.get_height() - 30
        return Button(
            x=btn_x, y=btn_y,
            width=self.inventory_btn_image.get_width(),
            height=self.inventory_btn_image.get_height(),
            text="", settings=self.settings,
            action=self._on_inventory_click,
            image_path=None  # 手动绘制按钮图片
        )

    def _init_inventory_elements(self):
        """初始化物品栏元素：根据角色装备列表数量，循环生成装备槽"""
        inventory_w = self.inventory_bg_image.get_width()
        inventory_h = self.inventory_bg_image.get_height()
        # 弹窗居中坐标
        inventory_x = (self.settings.screen_width - inventory_w) // 2
        inventory_y = (self.settings.screen_height - inventory_h) // 2

        # 1. 创建Back按钮（右下角，返回地图）
        back_btn = Button(
            x=inventory_x + inventory_w - self.settings.btn_width - 30,
            y=inventory_y + inventory_h - self.settings.btn_height - 20,
            width=self.settings.btn_width, height=self.settings.btn_height,
            text="Back", settings=self.settings,
            action=self._close_inventory,
            image_path=os.path.join(self.root_dir, self.settings.button_images_path["start_ui_button"])
        )

        # 2. 循环生成装备槽（数量=角色装备列表长度，当前5个）
        equip_slot_size = 110  # 单个装备槽尺寸（110x110）
        equip_count = len(self.equipments)  # 从角色装备列表获取数量
        if equip_count == 0:
            equip_count = 1  # 避免无装备时槽位异常

        # 计算装备栏总宽度和起始位置（确保居中）
        slot_spacing = 25  # 装备槽间距
        total_equip_width = equip_count * equip_slot_size + (equip_count - 1) * slot_spacing
        # 左侧预留300px给角色区，右侧预留50px边距
        max_available_width = inventory_w - 350
        # 水平居中修正
        equip_slot_start_x = inventory_x + 300
        if total_equip_width < max_available_width:
            equip_slot_start_x += (max_available_width - total_equip_width) // 2

        equip_slot_start_y = inventory_y + 120  # 装备栏顶部起始y
        equip_slots = []
        # 循环生成每个装备槽的Rect
        for i in range(equip_count):
            slot_x = equip_slot_start_x + i * (equip_slot_size + slot_spacing)
            slot_y = equip_slot_start_y
            equip_slots.append(pygame.Rect(slot_x, slot_y, equip_slot_size, equip_slot_size))

        # 3. 角色信息区域（左侧显示角色图和状态）
        player_info_rect = pygame.Rect(inventory_x + 150, inventory_y + 60, 220, 320)

        return {
            "inventory_rect": pygame.Rect(inventory_x, inventory_y, inventory_w, inventory_h),
            "back_btn": back_btn,
            "equip_slots": equip_slots,
            "player_info_rect": player_info_rect
        }

    def _on_inventory_click(self):
        """点击物品栏按钮：打开弹窗"""
        self.is_inventory_open = True

    def _close_inventory(self):
        """点击Back按钮：关闭物品栏弹窗"""
        self.is_inventory_open = False

    def _on_level_click(self, level_num: int):
        """点击关卡按钮：跳转战斗界面（预留接口）"""
        print(f"【地图】点击关卡 {level_num}，准备跳转战斗")
        if self.battle_jump_func and callable(self.battle_jump_func):
            self.battle_jump_func(level_num, self.player)  # 传入关卡号和角色实例
        self.running = False

    def _toggle_equipment(self, equip_index: int):
        """切换装备的装备状态"""
        if 0 <= equip_index < len(self.equipments):
            equip = self.equipments[equip_index]
            # 如果要装备当前物品，先卸下同类型的装备
            if not equip.is_equipped:
                self.player.unequip_same_type(equip.equip_type)
            # 切换装备状态
            equip.is_equipped = not equip.is_equipped
            print(f"【装备】{equip.name} {'已装备' if equip.is_equipped else '已卸下'}")

    def set_battle_jump(self, jump_func):
        """外部绑定战斗界面跳转函数（接口方法）"""
        self.battle_jump_func = jump_func

    def _draw_inventory(self):
        """绘制物品栏弹窗（显示角色状态+装备列表）"""
        elements = self.inventory_elements
        # 1. 绘制弹窗背景
        self.screen.blit(self.inventory_bg_image, elements["inventory_rect"].topleft)

        # 2. 绘制左侧角色信息（图片+动态状态）
        # 角色大图
        self.screen.blit(self.player_img, elements["player_info_rect"].topleft)
        # 角色状态文本（从角色实例获取动态数据）
        status_texts = [
            f"HP: {self.player.current_hp}/{self.player.max_hp}",
            f"ATK: {self.player.get_total_atk()}",
            f"DEFENSE: {self.player.get_total_defense()}",
            f"SPEED: {self.player.get_total_speed()}"
        ]
        # 绘制状态文本
        for i, text in enumerate(status_texts):
            text_surf = self.settings.font_small.render(text, True, self.settings.color_black)
            text_y = elements["player_info_rect"].top + self.player_img.get_height() + 25 + i * 32
            self.screen.blit(text_surf, (elements["player_info_rect"].left + 25, text_y))

        # 3. 绘制右侧装备槽（循环遍历角色的装备列表）
        for equip, slot_rect in zip(self.equipments, elements["equip_slots"]):
            # 加载装备图片
            try:
                equip_img = pygame.image.load(os.path.join(self.root_dir, equip.image_path)).convert_alpha()
                equip_img = pygame.transform.scale(equip_img, (70, 70))  # 装备图尺寸70x70
            except FileNotFoundError:
                print(f"【错误】未找到装备图片: {equip.image_path}")
                equip_img = pygame.Surface((70, 70), pygame.SRCALPHA)
                equip_img.fill((180, 180, 180, 200))

            # 绘制装备边框（已装备：橙色，未装备：灰色）
            border_color = self.settings.color_yellow if equip.is_equipped else self.settings.color_gray
            pygame.draw.rect(self.screen, border_color, slot_rect, 3, border_radius=3)

            # 绘制装备名称
            name_surf = self.settings.font_small.render(equip.name, True, self.settings.color_black)
            name_rect = name_surf.get_rect(centerx=slot_rect.centerx, top=slot_rect.top + 8)
            self.screen.blit(name_surf, name_rect)

            # 绘制装备图片（居中）
            img_rect = equip_img.get_rect(center=slot_rect.center)
            self.screen.blit(equip_img, img_rect)

            # 绘制装备属性（atk/defense/speed）
            attr_y = img_rect.bottom + 5
            attr_texts = [
                f"ATK: {equip.attack}",
                f"DEF: {equip.defense}",
                f"SPEED: {equip.speed}"
            ]
            for attr_text in attr_texts:
                attr_surf = self.settings.font_small.render(attr_text, True, self.settings.color_black)
                attr_rect = attr_surf.get_rect(centerx=slot_rect.centerx, top=attr_y)
                self.screen.blit(attr_surf, attr_rect)
                attr_y += 20

        # 4. 绘制Back按钮
        elements["back_btn"].draw(self.screen)

    def handle_events(self):
        """事件处理（分层：弹窗优先）"""
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                self.running = False

            # 弹窗打开时，优先处理弹窗内事件
            if self.is_inventory_open:
                self.inventory_elements["back_btn"].handle_event(event)
                
                # 处理装备点击事件
                if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:  # 左键点击
                    mouse_pos = pygame.mouse.get_pos()
                    # 检查是否点击了装备槽
                    for i, (equip, slot_rect) in enumerate(zip(self.equipments, self.inventory_elements["equip_slots"])):
                        if slot_rect.collidepoint(mouse_pos):
                            self._toggle_equipment(i)
                            break
            else:
                # 弹窗关闭时，处理地图按钮事件
                for btn in self.level_buttons:
                    btn.handle_event(event)
                self.inventory_button.handle_event(event)

    def draw(self):
        """绘制所有地图元素"""
        # 1. 绘制地图背景
        self.screen.blit(self.map_background, (0, 0))

        # 2. 绘制关卡按钮
        for btn in self.level_buttons:
            btn.draw(self.screen)

        # 3. 绘制右下角物品栏按钮
        self.screen.blit(self.inventory_btn_image, self.inventory_button.rect.topleft)

        # 4. 绘制物品栏弹窗（若打开）
        if self.is_inventory_open:
            self._draw_inventory()

        # 更新屏幕
        pygame.display.flip()

    def run(self):
        """地图界面主循环"""
        clock = pygame.time.Clock()
        self.music_player.stop_music()
        while self.running:
            clock.tick(self.settings.fps)
            self.handle_events()
            self.music_player.play_music("map")
            self.draw()


# ---------------------- 测试代码：创建装备列表、角色实例，运行地图 ----------------------
if __name__ == "__main__":
    # 1. 创建测试用装备列表（5个装备实例，外部接入核心）
    test_equipments = [
        Equipment(
            name="青铜剑",
            image_path="image/test_equip.png",
            is_equipped=True,
            atk=25,
            defense=5,
            speed=3,
            equip_type="weapon"  # 武器类型
        ),
        Equipment(
            name="皮甲",
            image_path="image/test_equip.png",
            is_equipped=False,
            atk=0,
            defense=18,
            speed=1,
            equip_type="armor"  # 盔甲类型
        ),
        Equipment(
            name="布鞋",
            image_path="image/test_equip.png",
            is_equipped=True,
            atk=0,
            defense=3,
            speed=8,
            equip_type="shoes"  # 鞋子类型
        ),
        Equipment(
            name="护腕",
            image_path="image/test_equip.png",
            is_equipped=False,
            atk=8,
            defense=2,
            speed=2,
            equip_type="bracelet"  # 护腕类型
        ),
        Equipment(
            name="玉佩",
            image_path="image/test_equip.png",
            is_equipped=True,
            atk=5,
            defense=10,
            speed=5,
            equip_type="accessory"  # 饰品类型
        )
    ]

    # 2. 创建测试用角色实例（包含外部装备列表）
    test_player = Character(
        name="Chang'an Swordsman",
        hp=320,
        max_hp=320,
        atk=70,  # 基础攻击力
        defense=40,  # 基础防御力
        speed=60,  # 基础速度
        image_big_path="image/test_charactor.png",  # 角色大图路径
        equipments=test_equipments  # 外部接入装备列表
    )

    # 3. 定义测试用战斗跳转函数（模拟跳转逻辑）
    def test_battle_jump(level_num: int, player: Character):
        """测试：打印跳转信息，实际项目中替换为BattleUI初始化"""
        print(f"\n【跳转】从地图关卡{level_num}进入战斗")
        print(f"【角色状态】HP: {player.current_hp}/{player.max_hp} | ATK: {player.get_total_atk()} | DEF: {player.get_total_defense()}")
        print(f"【携带装备】{[equip.name for equip in player.equipments if equip.is_equipped]}")
        # 实际战斗界面初始化逻辑（示例）：
        # from battle_ui import BattleUI
        # enemy = Enemy(...)  # 根据关卡创建敌人
        # battle_ui = BattleUI(player, enemy)
        # battle_ui.run()

    # 4. 初始化地图界面，传入角色实例（含外部装备列表）
    map_ui = MapUI(player=test_player)
    # 绑定战斗跳转函数
    map_ui.set_battle_jump(test_battle_jump)
    # 运行地图界面
    map_ui.run()
    sys.exit()